var runtimeConfig = null;

// 决战天下阶段赛 :对应的战场ID
var fightProgressMap = {    
    1:[1],      
    3:[2,3,4],
    9:[5,6,7,8,9,10,11,12,13],
}

// 城市行动路径
var cityMove = {    
    '1' : [4,7,9],
    '2' : [5,7,8],
    '3' : [6,8,9],    
    '4' : [1,7,9,10],
    '5' : [2,7,8,10],
    '6' : [3,8,9,10], 
    '7' : [1,2,4,5,10],
    '8' : [2,3,5,6,10],
    '9' : [1,3,4,6,10],   
    '10': [4,5,6,7,8,9], 
};

// 主城ID
var mainCities = [1,2,3];


exports._initRuntime = function() {
    runtimeConfig = gConfRuntime.battleWorld;
}

function BattleWorld() {
    this.end = 0;                   // (1/0)决战天下报名结束\9强\3强\1强阶段结束标志,在报名和战斗进行期间为0
    this.count = 0;                 // 决战天下当前进行的次数
    this.progress = 'register';     // 跨服战周期内的进度

    this.players = {                // 所有报名的玩家Player对象
        //uid : Player({ _id:uid, info:, status:{}, role:{}, team:{}, 'pet':})
    };

    this.registers = {              // 报名信息
        /*serverId : {uid:rank},*/  // 报名前一天擂台排名前100的玩家UID 
    };
        
    this.users = {                  // 玩家数据
        /*
        uid : {
            progress : 0,           // 玩家所在战场进度
            city :0,                // 玩家所在战场的城市ID
            score : 0,              // 玩家杀敌积分
            kill : 0,               // 玩家连斩数
            energy : 0,             // 玩家携带体力
        }
        */ 
    };

    this.servers = {                // 各个参战服务器的数据
        /*
        server : {
            server_field : 0,       // 服务器战区ID
            battle_field : 0,       // 战场ID
            main_city : 0,          // 主城ID
            score : 0,              // 占城积分
            fight_force : 0,        // 总战力
            worth : 0,              // 身价
        }
        */
    };

    this.cities = {                 // 占城情况
        /*
        serverFieldId_battleFieldId_cityId : {    
            time : now,             // 初始化为分配战场时的时间
            server : 0,             // 服务器ID
        }
        */
    };
    
    this.historyScores = {          // 历史积分
        /*
        serverFieldId_battleFieldId_serverId : {
            fight_force : 0,        // 历史战斗力 
            score : 0,              // 历史积分
        }
        */ 
    };

    this.topOnes = {                // 各个战场的神将
        /*
        serverFieldId_battleFieldId : []; 
        */
    };
    
    // 内存数据
    this.userServers = {            // 玩家的服务器ID映射
        /*
        uid : serverId,
        */
    };

    this.serverTotalScores = {      // 当前progress(9/3/1)下每个服务器的实时总积分
        /*
        serverId : score,
        */    
    };

    this.cityScoreUpdates = {       // 当前progress(9/3/1)下占城积分更新时间
        /*
        serverFieldId_battleFieldId : time, 
        */ 
    };

    this.currentPersonRanks = {     // 当前progress(9/3/1)下战场实时排名
        /*
        serverFieldId_battleFieldId : {'rank':[], 'last_update':0},
        */ 
    };

    this.cityMembers = {            //当前progress(9/3/1)下每个服务器战区每个战场每个城市中玩家
        /*
        serverFieldId_battleFieldId_cityId : {
            uid: 1,
        }
        */
    }; 

    this.messages = {               // 各个战场的消息
        /* 
        serverFieldId_battleFieldId : [], 
        */
    };

    this.reports = {                // 战报
        /*
        uid : [{
            name:'',                // 攻击方名字 
            time:0,                 // 攻击时间
            succ:0,                 // 0/1 攻击方胜利or失败
            energy:0,               // 被攻击方损失的体力
            score:0,                // 被攻击方获取的积分
        }],
        */
    };

    this.serverFieldMax = 0;        // 本届比赛服务器战区数目 
    this.serverNumOfServerField = 27;  // 每个服务器战区所需服务器数目

    this.open = 1;                  // 0/1 跨服战是否正常开启
    this.fighting = false;          // 是否正在战斗计算
    this.isEndWar = false;          // endWar 是否已经被执行过
    this.calculating = false;       // 战场初始化或战场结算时的标记,为true时,不能进行任何操作
    this.updates = {};
}

BattleWorld.create = function() {

    var battleWorld = {
        _id: 'battle_world', 
        progress: 'open',
        end : 0,
        count : 0,
        registers: {},
        users : {},
        servers : {},
        cities : {},
        history_scores : {},
        top_ones:{},
    };

    gDBWorld.insert(battleWorld, function(err, result){});
};

BattleWorld.prototype = {
    init : function(callback) {
        gDBWorld.findOne({_id : 'battle_world'}, {}, function(err, doc){
            if( doc ) {
                this.progress = doc.progress;
                this.end = doc.end;
                this.count = doc.count;
                this.registers = doc.registers;
                this.users = doc.users;
                this.servers = doc.servers;
                this.cities = doc.cities;
                this.historyScores = doc.history_scores;
                this.topOnes = doc.top_ones;
                this._init(callback);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    _init : function(callback) {

        // 初始化服务器战区数目
        var servers = Object.keys(this.registers);
        this.serverFieldMax = Math.floor(servers.length / this.serverNumOfServerField);
        if( this.progress != 'register' && this.progress != 'open' ) {
            // 初始化userServers
            var registers = this.registers;
            for( var id in registers ) {
                var register = registers[id];
                for( var uid in register ) {
                    this.userServers[uid] = +id; 
                } 
            }

            // 初始化cityMembers 
            var users = this.users;
            for( var uid in users ) {
                var userData = users[uid];
                if( userData.progress != this.progress ) {
                    continue; 
                }
                
                var serverData = this.getServer(this.userServers[uid]);
                var members = this.getBattleFieldCityMembers(serverData.server_field, serverData.battle_field, userData.city);
                members[uid] = 1;
            }
            
            // 初始化当前progress的players
            var cursor = gDBUser.find();
            cursor.each(function(err, item){
                if( err ) {
                    ERROR(err);
                    return;
                }

                if( item ) {
                    var uid = item._id;
                    var userData = this.users[uid];
                    if( userData && (this.progress == userData.progress) ) {
                        var player = new Player(uid);
                        player.initWithUniverseData(item);
                        this.players[uid] = player;
                    }
                }

                if( cursor.isClosed() ) {
                    callback && callback(true);
                }
            }.bind(this));

        }else{
            callback && callback(true);
        }
    },

    addUpdate : function(key, value) {
        this.updates[key] = value;
    },

    save : function(forceSave, callback) {
        if( !forceSave && Object.keys(this.updates).length <= 10 ) {
            callback && callback(true);
            return;
        }
        
        var updates = this.updates;
        gDBWorld.update({_id : 'battle_world'}, {$set:updates}, function(err, result){
            if( err ) {
                ERROR(err);
                ERROR(updates);
                callback && callback(false);
            }else {
                callback && callback(true);
            }
        });

        this.updates = {};
    },

    saveBattleWorld : function() {
        var battleWorld = {
            _id: 'battle_world', 
            progress: this.progress,
            end : this.end,
            count : this.count,
            registers: this.registers,
            users: this.users,
            servers: this.servers,
            cities: this.cities,
            history_scores : this.historyScores,
            top_ones : this.topOnes,
        };

        gDBWorld.save(battleWorld, function(err, result){
            if( err ) {
                ERROR(err);
            }
        });

        this.updates = {};
    },

    addUser : function(uid, serverFieldId, battleFieldId, mainCity, serverId, fightForce) {

        var user = {
            'score': gConfGlobal.BattleWorldBaseScore, 
            'kill': 0,
            'energy': gConfGlobal.BattleWorldPersonEnernyMax,
            'city': +mainCity,
            'progress': +this.progress,
        };

        this.users[uid] = user;
            
        this.addUpdate('users.'+uid, user);

        var members = this.getBattleFieldCityMembers(serverFieldId, battleFieldId, mainCity);
        members[uid] = 1;
        this.servers[serverId].fight_force += fightForce; 
        this.addUpdate('servers.'+serverId, this.servers[serverId]);

        this.userServers[uid] = +serverId;

        return user;
    },

    updateUser : function(uid, serverFieldId, battleFieldId, mainCity, serverId) {

        var user = {
            'score': gConfGlobal.BattleWorldBaseScore, 
            'kill': 0,
            'energy': gConfGlobal.BattleWorldPersonEnernyMax,
            'city': +mainCity,
            'progress': +this.progress,
        };

        this.users[uid] = user;
            
        this.addUpdate('users.'+uid, user);

        var members = this.getBattleFieldCityMembers(serverFieldId, battleFieldId, mainCity);
        members[uid] = 1;

        return user;
    },

    getUser : function(uid) {
        return this.users[uid] || null; 
    },

    getPlayer : function(uid) {
        return this.players[uid] || null; 
    },

    getServer : function(serverId) {
        return this.servers[serverId] || null;
    },

    getUserServerId : function(uid) {
        return this.userServers[uid] || 0; 
    },

    haveQualification : function(serverId, uid) {
        // 是否有资格参加比赛 
        return (this.servers[serverId] && this.registers[serverId][uid]) || 0;
    },

    isUnderWar : function() {
        var isUnderWar = false;
        if( !this.end && this.fighting && 
            (this.progress in fightProgressMap) ) {
            isUnderWar = true; 
        } 

        return isUnderWar;
    },

    isUnderSupportReward : function() {
        // 是否在领取支持奖励的时间
        var isUnderReward = false;
        if( this.end && !this.fighting && 
            (this.progress in fightProgressMap) ) {
            isUnderReward = true; 
        } 

        return isUnderReward;
    },

    getBattleFieldCities : function(serverFieldId, battleFieldId) {
        var cities = this.cities;
        var battleFieldCities = {};
        for(var city = 1; city <= 10; city++) {
            var cityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, city);
            battleFieldCities[city] = cities[cityIndex] || {time:common.getTime(), server:0};
        }

        return battleFieldCities;
    },
    
    getBattleFieldCityMembers : function(serverFieldId, battleFieldId, city) {
        var cityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, city);
        if( !(cityIndex in this.cityMembers) ) {
            this.cityMembers[cityIndex] = {}; 
        }

        return this.cityMembers[cityIndex]; 
    },

    getCurrentPersonRank : function(serverFieldId, battleFieldId) {
        // 只计算当前progress下的战场数据 
        if( fightProgressMap[this.progress] && fightProgressMap[this.progress].indexOf(+battleFieldId) < 0 ) {
            return; 
        }

        var now = common.getTime();

        if( !(serverFieldId in this.currentPersonRanks) ) {
            this.currentPersonRanks[serverFieldId] = {};
        }

        if( !(battleFieldId in this.currentPersonRanks[serverFieldId]) ) {
            this.currentPersonRanks[serverFieldId][battleFieldId] = {'rank':[], 'last_update':0};
        }

        var oldRank = this.currentPersonRanks[serverFieldId][battleFieldId];
        if( (now - oldRank.last_update) > 30 ) {
            var personRank = [];
            var battleFieldCities = this.getBattleFieldCities(serverFieldId, battleFieldId);
            for( var city in battleFieldCities ) {
                var battleFieldCityMembers = this.getBattleFieldCityMembers(serverFieldId, battleFieldId, city);
                for( var uid in battleFieldCityMembers ) {
                    var userData = this.getUser(uid);
                    var serverId = this.getUserServerId(uid);
                    if( !serverId ) continue;

                    var rank = {
                        'uid': +uid,
                        'name': (this.players[uid] ? this.players[uid].user.info.un : ''), 
                        'score': userData.score + this.servers[serverId].score,
                        'kill': userData.kill, 
                        'server': serverId, 
                    }

                    personRank.push(rank);
                }
            }

            personRank.sort(function(a, b){return b.score - a.score;});
            personRank = personRank.slice(0, 22);
            oldRank.rank = personRank;
            oldRank.last_update = now;
        }

        return oldRank.rank;
    },

    getPersonRankOfServer : function(serverFieldId, battleFieldId, serverId) {
        // 获取每个服务器内部排名
        var personRank = [];
        var cities= this.getBattleFieldCities(serverFieldId, battleFieldId);
        for( var city in cities ) {
            var cityData = cities[city]; 
            if( +cityData.server != serverId ) {
                continue; 
            }

            var members = this.getBattleFieldCityMembers(serverFieldId, battleFieldId, city);
            for( var uid in members ) {
                var userData = this.getUser(uid);
                if( !userData ) {
                    continue; 
                }

                var rank = {
                    'uid': +uid,
                    'score': userData.score + this.servers[serverId].score, 
                }

                personRank.push(rank);
            }
        }

        personRank.sort(function(a, b){return b.score - a.score;});

        return personRank.slice(0,2);
    },

    genTopOnes : function(serverFieldId, battleFieldId, forceSave) {
        // 只计算当前progress下的战场数据 
        var progress = this.progress;
        if( fightProgressMap[progress] && fightProgressMap[progress].indexOf(+battleFieldId) < 0 ) {
            return; 
        }

        var battleFieldIndex = util.format('%d_%d', serverFieldId, battleFieldId);

        var topOne = [];
        if( !(battleFieldIndex in this.topOnes) ) {
            this.topOnes[battleFieldIndex] = topOne;    
        }

        var servers = this.genBattleFieldServerRank(serverFieldId, battleFieldId);
    
        // 每个战场第一名服务器个人积分前1名为神将
        var rankDatas = this.getPersonRankOfServer(serverFieldId, battleFieldId, servers[0].server);
        if( rankDatas[0] ) {
            topOne.push(+rankDatas[0].uid);
        }
        
        if( forceSave ) {
            this.addUpdate(util.format('top_ones.%s', battleFieldIndex), this.topOnes[battleFieldIndex] );  
        }
    },

    updateServerScore : function(serverFieldId, battleFieldId){
        // 只计算当前progress下的战场数据 
        if( this.end || (fightProgressMap[this.progress] && 
            fightProgressMap[this.progress].indexOf(+battleFieldId)) < 0 ) {
            return; 
        }

        // 更新城池占领积分
        var battleFieldIndex = util.format('%d_%d', serverFieldId, battleFieldId);
        var now = common.getTime();
        if( !(battleFieldIndex in this.cityScoreUpdates) ) {
            this.cityScoreUpdates[battleFieldIndex] = 0; 
        }

        if( (now - this.cityScoreUpdates[battleFieldIndex]) < 60 ) {
            return; 
        }

        var battleFieldCities = this.getBattleFieldCities(serverFieldId, battleFieldId);
        var addScores = {};
        for( var city in battleFieldCities ) {
            var cityData = battleFieldCities[city];
            var cityOccupiedServer = this.cityOccupiedServer(serverFieldId, battleFieldId, city);
            if( !cityOccupiedServer ) continue;

            var timePassed = now - cityData.time;
            var score = Math.floor(timePassed/3600*gConfBattleWorldFieldCity[city].ScorePerHour);

            cityData.time = now;
            this.addUpdate(util.format('cities.%d_%d_%d', serverFieldId, battleFieldId, city), cityData);

            if( !(cityOccupiedServer in addScores) ) {
                addScores[cityOccupiedServer] = score;
            }else{
                addScores[cityOccupiedServer] += score;
            }
        }

        for( var server in addScores ) {
            this.servers[server].score += addScores[server];
            this.addUpdate(util.format('servers.%s', server), this.servers[server]);
            this.updateServerTotalScore(+server, battleFieldId);
        }

        this.cityScoreUpdates[battleFieldIndex] = now; 
    },

    updateServerTotalScore : function(serverId, battleFieldId) {
        // 只计算当前progress下的战场数据 
        if( fightProgressMap[this.progress] && 
            fightProgressMap[this.progress].indexOf(+battleFieldId) < 0 ) {
            return; 
        }

        var members = this.registers[serverId];
        var serverMemberNum = 0;
        var totalScore = 0;
        for ( var uid in members ) {
            var userData = this.getUser(+uid);
            if( !userData || (userData.progress != this.progress) 
                || (this.getUserServerId(uid) != serverId) ) continue;

            serverMemberNum += 1; 
            totalScore += userData.score;
        }

        totalScore += this.servers[serverId].score * serverMemberNum;
        this.serverTotalScores[serverId] = totalScore;

        return totalScore;
    },

    genBattleFieldServerRank : function(serverFieldId, battleFieldId){
        // 每个战场的服务器的排序 只计算当前progress下的战场数据
        if( fightProgressMap[this.progress] && fightProgressMap[this.progress].indexOf(+battleFieldId) < 0 ) {
            return; 
        }

        var servers = [];
        var cities = this.getBattleFieldCities(serverFieldId, battleFieldId);
        for( var i=1; i<=3; i++ ) {
            var serverId = cities[i].server;
            if( !serverId ) continue;
            this.updateServerTotalScore(serverId, battleFieldId);
            var serverData = this.getServer(serverId);
            servers.push({
                'server':+serverId, 
                'score': this.serverTotalScores[serverId]|| 0,
            });
        }

        servers.sort(function(a, b) { return b.score - a.score; } );

        return servers;
    },

    getBattleFieldHistoryServerRank : function(serverFieldId, battleFieldId){
        // 每个战场的服务器的排序 只计算已经完成阶段比赛的数据
        var servers = [];
        var cities = this.getBattleFieldCities(serverFieldId, battleFieldId);
        for( var i=1; i<=3; i++ ) {
            var serverId = cities[i].server;
            if( !serverId ) continue;
            var serverIndex = util.format('%d_%d_%d', serverFieldId, battleFieldId, serverId);

            var serverData = this.historyScores[serverIndex] || {fight_force : 0, score : 0};
            servers.push({
                'server':+serverId, 
                'score': serverData.score,
            });
        }

        servers.sort(function(a, b) { return b.score - a.score; } );

        return servers;
    },

    isServerOnCurProgress : function(serverId) {
        var serverData = this.getServer(serverId);
        if( !serverData ) {
            return false; 
        } 

        var isOn = false;
        var curProgress = this.progress;
        if( (curProgress in fightProgressMap) &&
            (fightProgressMap[curProgress].indexOf(+serverData.battle_field) >= 0) ) {
            isOn  = true;
        }

        return isOn;
    },

    addMessage : function(serverFieldId, battleFieldId, message) {
        var battleFieldIndex = util.format('%d_%d', serverFieldId, battleFieldId);
        var messages = this.messages[battleFieldIndex];
        if( !messages ) {
            messages =[];
            this.messages[battleFieldIndex] = messages;
        }

        if( messages.length >= 3 ) {
            messages.shift(); 
        }

        messages.push(message);
    },

    getMessage : function(serverFieldId, battleFieldId) {
        var battleFieldIndex = util.format('%d_%d', serverFieldId, battleFieldId);
        var messages = this.messages[battleFieldIndex];
        if( !messages ) {
            messages =[];
            this.messages[battleFieldIndex] = messages;
        }

        return messages;
    },

    addReport : function(uid, report) {
        
        if( !(uid in this.reports) ) {
            this.reports[uid] = [];
        } 
        
        var reports = this.reports[uid];
        if( reports.length >= 10 ) {
            reports.shift(); 
        }

        reports.push(report);
    },

    getReport : function(uid) {
        var reports = this.reports[uid] ? this.reports[uid] : [];
        this.reports[uid] = [];
        return reports;
    },

    fight : function(playerUid, enemyUid, isAddAttack, addToWhich, callback) {
        var player = this.players[playerUid];
        var enemy = this.players[enemyUid];
        if( !player || !enemy ) {
            callback && callback(null); 
            return;
        }
        
        var playerFighter = new Fighter();
        playerFighter.initWithPlayer(player, null, true, ((isAddAttack && 'attack' == addToWhich) ? 'battle_world' : null));

        var enemyFighter = new Fighter();
        enemyFighter.initWithPlayer(enemy, null, true, ((isAddAttack && 'defence' == addToWhich) ? 'battle_world' : null));

        var battleReport = playerFighter.fight(enemyFighter);
        callback && callback(battleReport); 
    },

    backHome : function(serverFieldId, battleFieldId, uid) {
        var userData = this.getUser(uid);
        
        var userServerId = this.getUserServerId(uid);
        var mainCity = +this.servers[userServerId].main_city;
        if( userData.city == mainCity ) return;

        return this.move(serverFieldId, battleFieldId, uid, mainCity);
    },

    move : function(serverFieldId, battleFieldId, uid, toCity) {
        var leaveEmpty = false;  // 返回离开后是否空城

        var userData = this.getUser(uid);
        var fromCity = +userData.city;

        if( fromCity == toCity ) return;
         
        var fromCityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, fromCity);
        var toCityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, toCity);

        var fromCityOccupiedServer = this.cityOccupiedServer(serverFieldId, battleFieldId, fromCity);
        var fromCityWarField = this.getBattleFieldCityMembers(serverFieldId, battleFieldId, fromCity);
        delete fromCityWarField[uid];
        
        var cities = this.cities;

        // 离开后,检查空城,计算积分
        var cityOccupiedServer = this.cityOccupiedServer(serverFieldId, battleFieldId, fromCity);
        if( mainCities.indexOf(fromCity) < 0 && !cityOccupiedServer && fromCityOccupiedServer ) {
            var cityData = cities[fromCityIndex];
            var now = common.getTime();
            var timePassed = now - cityData.time;
            var score = Math.floor(timePassed/3600*gConfBattleWorldFieldCity[fromCity].ScorePerHour);
            this.servers[fromCityOccupiedServer].score += score;

            this.addUpdate(util.format('servers.%d', fromCityOccupiedServer), 
                                this.servers[fromCityOccupiedServer]);
            this.updateServerTotalScore(fromCityOccupiedServer, battleFieldId);

            cityData.server = 0;
            cityData.time = common.getTime();
            this.addUpdate(util.format('cities.%s', fromCityIndex), cityData);

            leaveEmpty = true;
        }

        var toCityWarField = this.getBattleFieldCityMembers(serverFieldId, battleFieldId, toCity);
        // 进入空城
        cityOccupiedServer = this.cityOccupiedServer(serverFieldId, battleFieldId, toCity);
        if( mainCities.indexOf(toCity) < 0 && !cityOccupiedServer ) {
            var cityData = cities[toCityIndex];

            cityData.server = this.getUserServerId(uid);
            cityData.time = common.getTime();

            this.addUpdate(util.format('cities.%s', toCityIndex), cityData);
        }

        toCityWarField[uid] = 1;

        userData.city = +toCity;
        this.addUpdate(util.format('users.%d', uid), userData);

        return leaveEmpty;
    },

    cityOccupiedServer : function(serverFieldId, battleFieldId, city) {
        var cityServer = 0; 
        var cityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, city);
        if( mainCities.indexOf(+city) >= 0 ) {
            // 如果city 为主城
            cityServer = this.cities[cityIndex].server;
        }else {
            var members = this.getBattleFieldCityMembers(serverFieldId, battleFieldId, city);
            var memberUids = Object.keys(members);
            if( memberUids.length > 0 ) {
                var uid = memberUids[0];
                cityServer = this.getUserServerId(uid);
            }
            
            var cityData = this.cities[cityIndex]; 
            if( cityServer && cityData && !cityData.server ) {
                cityData.server = cityServer;
            }
        }

        return cityServer;
    },

    getCurSupportProgress : function() {
        // 获取当前可以支持的progress 
        var supportProgress = 0;
        var progress = this.getProgress().progress;    
        if( progress == 'replay' && this.progress == 'register' ) {
            supportProgress = 9; 
        }else if( this.end && progress == 'replay' 
            && (this.progress == 9 || this.progress == 3) ) {
            supportProgress = this.progress/3;
        }

        return supportProgress;
    },

    getEndProgress : function() {
        // 获取当前最近结束的progress
        var endProgress = 0;
        var curProgress = this.progress;
        if( !(curProgress in fightProgressMap) || 
            (+curProgress == 9 && !this.end) ) {
            endProgress = 0; 
        }else {
            if( this.end ) {
                endProgress = curProgress; 
            }else {
                endProgress = curProgress*3; 
            }
        }

        return endProgress;
    },

    getBattleFieldOfServerInProgress : function(serverFieldId, serverId, progress) {
        // 获取已经过期的progress(9/3/1)下服务器的战场ID 
        if( !serverId || !(progress in fightProgressMap) ) {
            return 0; 
        }

        var battleFieldId = 0;
        if( +progress == this.progress ) {
            battleFieldId = this.getServer(serverId).battle_field; 
        }else {
            var battleFields = fightProgressMap[progress];
            var find = false;
            for( var i =0, len = battleFields.length; i < len; i++ ) {
                battleFieldId = battleFields[i];
                for( var city = 1; city <= 3; city++ ) {
                    var cityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, city);
                    if( +this.cities[cityIndex].server == +serverId ) {
                        find = true;
                        break; 
                    }
                }
                
                if( !find ) {
                    continue; 
                }

                break;
            } 
        }
    
        return battleFieldId;
    },

    prepareBattleWorld : function() {
        // 准备分配战场
        var servers = Object.keys(this.registers);
        servers = servers.sort(function(a, b) { return a - b;});
        this.serverFieldMax = Math.floor(servers.length / this.serverNumOfServerField);
        var now = common.getTime();
        var nextProgress = 9;
        for(var i = 1,max = this.serverFieldMax; i <= max; i++) {
            var serverFieldId = i;
            var selectServers = servers.splice(0,this.serverNumOfServerField);  
            selectServers = selectServers.sort(function(a, b) {return (Math.random() > 0.5) ? 1 : -1});
            
            for( var progress in fightProgressMap ) {
                var battleFields = fightProgressMap[progress];
                for( var j = 0, len = battleFields.length; j < len; j++ ) {
                    var battleFieldId = battleFields[j];
                    var battleFieldServers = [];
                    if( +progress == nextProgress ) {
                        battleFieldServers = selectServers.splice(0, 3);
                        battleFieldServers.sort(function(a, b){return a -b;});
                    }

                    for(var city = 1; city <= 10; city++) {
                        var cityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, city);
                        this.cities[cityIndex] = {
                            time:now,
                            server:0,
                        };

                        if( city > 3 || (+progress != nextProgress) ) {
                            continue;
                        }

                        var serverId = +battleFieldServers[city - 1];
                        this.cities[cityIndex].server = serverId; 
                        this.servers[serverId] = {
                            server_field : serverFieldId,
                            battle_field : battleFieldId,
                            main_city : city,
                            score : 0,
                            fight_force : 0,
                            worth : 0,
                        }; 
                    }
                }
            }
        }
    },

    initWar : function(progress, forceSave) {
        // 初始化9强\3强\1强赛数据
        if( !(progress in fightProgressMap) ) {
            return; 
        }

        this.serverTotalScores = {};
        this.cityScoreUpdates = {};
        this.currentPersonRanks = {};
        this.cityMembers = {};
        this.messages = {};
        this.reports = {};
        this.isEndWar = false; 
        if( +progress == 9 ) {
            return; 
        }
        
        var preProgress = progress*3;
        var now = common.getTime();
        // 将上一个阶段对应战场的第一名服务器数据分配到即将开始的城市中
        // 选出上一个阶段对应战场的第一名
        var promotionServers = {}; 
        for( var i = 1,max = this.serverFieldMax; i <= max; i++ ) {
            var serverFieldId = i;
            if( !(serverFieldId in promotionServers) ) {
                promotionServers[serverFieldId] = [];
            }

            for( var j = 0, len = fightProgressMap[preProgress].length; j < len; j++ ) {
                var battleFieldId = fightProgressMap[preProgress][j];
                var servers = this.getBattleFieldHistoryServerRank(serverFieldId, battleFieldId);
                var promotionServerId = servers[0].server;
                if( (servers[0].score == servers[1].score) && 
                    (servers[0].score == servers[2].score) ) {
                    promotionServerId = Math.min(Math.min(servers[0].server, servers[1].server), servers[2].server);
                }else if( (servers[0].score == servers[1].score) ) {
                    promotionServerId = Math.min(servers[0].server, servers[1].server);
                }

                promotionServers[serverFieldId].push(+promotionServerId);
            }
        }

        for(var i = 1,max = this.serverFieldMax; i <= max; i++) {
            var serverFieldId = i;
            var selectServers = promotionServers[serverFieldId];  
            for(var j = 0, len = Math.floor(selectServers.length/3); j < len; j++) {
                var battleFieldId = fightProgressMap[progress][j];
                var battleFieldServers = selectServers.splice(0, 3);
                battleFieldServers.sort(function(a, b){return a -b;});
                for(var city = 1; city <= 10; city++) {
                    var cityIndex = util.format('%d_%d_%d',serverFieldId, battleFieldId, city);
                    var cityData = {
                        time:now,
                        server:0,
                    };
                    
                    if( forceSave ) {
                        this.addUpdate(util.format('cities.%s', cityIndex), cityData);
                    }

                    this.cities[cityIndex] = cityData; 

                    if( city > 3 ) {
                        continue;
                    }

                    var serverId = +battleFieldServers[city - 1];
                    cityData.server = serverId; 
                    
                    var serverData = this.servers[serverId];
                    serverData.battle_field = battleFieldId;
                    serverData.main_city = city;
                    serverData.score = 0;
                    if( forceSave ) {
                        this.addUpdate(util.format('servers.%s', serverId), serverData);
                    }
                }
            }
        }

    },

    endWar : function(progress, forceSave) {
        // 结算9强\3强\1强赛数据
        if( !(progress in fightProgressMap) ) {
            return; 
        }

        if( this.isEndWar ) return;
        
        var endWarBattleFields = fightProgressMap[progress];
        for( var serverFieldId = 1; serverFieldId <= this.serverFieldMax; serverFieldId++ ) {
            for( var i = 0, len = endWarBattleFields.length; i < len; i++ ) {
                var battleFieldId = endWarBattleFields[i]; 
                this.updateServerScore(serverFieldId, battleFieldId);
                var servers = this.genBattleFieldServerRank(serverFieldId, battleFieldId);

                for( var j = 0, max = servers.length; j < max; j++ ) {
                    var serverId = servers[j].server; 
                    var serverIndex = util.format('%d_%d_%d', serverFieldId, battleFieldId, serverId);
                    if( serverIndex in this.historyScores ) {
                        continue; 
                    }
                    
                    serverData = this.getServer(serverId);
                    var historyScore = {fight_force:serverData.fight_force, score:this.serverTotalScores[serverId]}; 
                    this.historyScores[serverIndex] = historyScore;
                    if( forceSave ) {
                        this.addUpdate(util.format('history_scores.%s', serverIndex), historyScore);
                    }
                }

                this.genTopOnes(serverFieldId, battleFieldId, forceSave); 
            }
        }
        
        this.isEndWar = true;
    },

    reset : function(count) {
        this.count = count;
        this.end = 0;
        this.players = {};
        this.registers = {};
        this.users = {};
        this.servers = {};
        this.cities = {};
        this.historyScores = {};
        this.serverTotalScores = {};
        this.cityScoreUpdates = {};
        this.currentPersonRanks = {};
        this.topOnes = {};
        this.cityMembers = {};
        this.messages = {};
        this.reports = {};
        this.updates = {};
        this.progress = 'register';
        this.saveBattleWorld();
    },

    tick : function() {
        var curCount = runtimeConfig.getRound();
        if (this.count != curCount) {
            LOG(util.format('count=%d reseted curCount=%d', this.count, curCount));
            this.reset(curCount); 
            return;
        }


        // 第一次必须进入报名阶段
        var progress = this.getProgress();
        if( this.progress == 'open' && progress.progress != 'register' ) return;
        
        if( ('register' == progress.progress) || 
            (('replay' == progress.progress) && this.end ) ) {
            this.fighting = false; 
        }else {
            this.fighting = true; 
        }
        
        if( progress.progress != 'register' && Object.keys(this.registers).length < 27 ) {
            // 参战人数不够,战斗不能正常开启
            this.open = 0;
            return; 
        }

        if( progress.progress == this.progress ) {
            return; 
        }

        this.open = 1;

        if ('register' == progress.progress) {
            if (this.progress != progress.progress) {
                LOG(util.format('count=%d reseted curCount=%d this.progress=%s curProgress=%s', 
                    this.count, curCount, this.progress, progress.progress));
                this.reset(curCount);
            }
            return;
        }
        
        if( ('register' == this.progress) && ('replay' == progress.progress) && !this.end ) {
            // 对报名的服务器按服务器ID大小进行排序,从小到大每27个服为一个战区,
            // 并且将每个战区的服务器随机分配到9强战场中的相应主城
            this.calculating = true;
            this.prepareBattleWorld() 
            this.end = 1;
            this.calculating = false;
            this.saveBattleWorld();
            return;
        }else if( (progress.progress in fightProgressMap) 
            && (this.progress != progress.progress) && this.end ) {
            // 9强\3强\1强赛前初始化战区数据
            this.calculating = true;
            var forceSave = true;
            this.initWar(progress.progress, forceSave); 
            this.end = 0;
            var curProgress = +progress.progress;
            this.progress = curProgress 
            this.addUpdate('end', 0);
            this.addUpdate('progress', curProgress);
            this.calculating = false;
            this.save(forceSave);
            return;
        }else if( ('replay' == progress.progress) && (this.progress in fightProgressMap ) && !this.end ) {
            // 9强\3强\1强赛时间到达后结算 
            this.calculating = true;
            var forceSave = true;
            this.endWar(this.progress, forceSave);
            this.end = 1;
            this.addUpdate('end', 1);
            this.calculating = false;
            this.save(forceSave);
            return;
        }
    },

    getProgress : function() {

        var nowDate = new Date();
        var nowWeekHour = nowDate.getDay() * 24 + nowDate.getHours() + nowDate.getMinutes() / 60;
        var allWeekHour = 7 * 24;

        var matchProgress = 'replay';
        var round = 0;

        for( var progress in gConfBattleWorldSchedule ) {
            var progressConf = gConfBattleWorldSchedule[progress];
            var startWeekHour = progressConf.StartWeek * 24 + progressConf.StartTime;
            
            var nowHour = nowWeekHour;
            if( nowHour < startWeekHour ) {
                nowHour += allWeekHour;
            }

            var passHour = nowHour - startWeekHour;
            if( passHour <= progressConf.KeepHour ) {
                matchProgress = progress;
                break;
            }
        }

        return {'progress':matchProgress};
    },

    register : function(serverId, users){
        var battleWorld = this;  
        var updates = {};
        updates['registers.'+serverId] = users;
        gDBWorld.update({_id : 'battle_world'}, {$set:updates}, function(err, result){
            if( err ) {
                ERROR(err);
            }else {
                battleWorld.registers[serverId] = users;
                LOG(util.format('count=%d server=%d register users=%j', battleWorld.count, serverId, users));
            }
        });
    },

    saveTeam : function(user) {
        gDBUser.save(user, function(err, result){
            if( err ) {
                ERROR(err);
            }else {
                
                var uid = user._id;
                var player = new Player(uid);
                player.initWithUniverseData(user);
                this.players[uid] = player;
            }    
        }.bind(this));
    },

}

exports.register = function(req, res, resp) {
    var serverId = req.args.server;
    do {
        // 时间限制
        if( gBattleWorld.getProgress().progress != 'register' ) {
            resp.code = 1; resp.desc = 'not regist time'; break;
        }
        
        gBattleWorld.tick();
        if( serverId in gBattleWorld.registers ) {
            LOG(util.format('count=%d server=%d register exist', gBattleWorld.count, serverId));
            break;
        }

        gBattleWorld.register(serverId, req.args.users);

    }while(false);

    onReqHandled(res, resp);
}

exports.get = function(req, res, resp) {
    var uid = req.uid;
    var serverId = req.args.server;
    do {
        var register = 0;
        var qualification = 0;
        var userNewProgress = 0;
        
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.open ) {
            resp.data.open = 0; 
            break;
        }

        if( gBattleWorld.haveQualification(serverId, uid) ) {
            qualification = 1;  
        }
        
        if( gBattleWorld.getProgress().progress == 'register' ) {
            if( (serverId in gBattleWorld.registers) ) {
                register = 1; 
            }    

        }else if( Object.keys(gBattleWorld.servers).length > 0 ) {
            var serverData = gBattleWorld.getServer(serverId);
            if( !serverData ) {
                resp.data.open = 0; 
                break; 
            }
            
            register = 1;

            var serverFieldId = serverData.server_field;
            var cities = gBattleWorld.cities;
            var battleFields= {};
            var curProgress = gBattleWorld.progress;

            var selectProgress = 0;
            if( curProgress == 'register' ) {
                selectProgress = 9;
            }else {
                selectProgress = curProgress;
            }
            
            // 获取当前progress以及该progress前的比赛对应的服务器战场数据
            for( var progress in fightProgressMap ) {
                if( +progress < selectProgress ) {
                    continue; 
                } 
                
                for( var i = 0, len = fightProgressMap[progress].length; i < len; i++ ) {
                    var battleFieldId = fightProgressMap[progress][i];
                    if( !(battleFieldId in battleFields) ) {
                        battleFields[battleFieldId] = {};
                    }

                    var cities = gBattleWorld.getBattleFieldCities(serverFieldId, battleFieldId);
                    if( +progress == selectProgress ) {
                        // 更新当前还在战斗的服务器积分
                        gBattleWorld.updateServerScore(serverFieldId, battleFieldId);
                    }

                    for( var city = 1; city <= 3; city++ ) {
                        var cityData = cities[city]; 
                        var server = cityData.server;
                        var serverInfo = gBattleWorld.getServer(server);
                        var serverIndex = util.format('%d_%d_%d', serverFieldId, battleFieldId, server);
                        var retServerData = {
                            'worth' : serverInfo.worth, 
                            'fight_force' : 0,
                            'score' : 0,
                        };

                        battleFields[battleFieldId][server] = retServerData;
                        if( serverIndex in gBattleWorld.historyScores ) {
                            var historyServerData = gBattleWorld.historyScores[serverIndex];
                            retServerData.fight_force = historyServerData.fight_force; 
                            retServerData.score = historyServerData.score; 
                            continue;
                        }

                        if( +progress == selectProgress && !gBattleWorld.end ) {
                            retServerData.fight_force = serverInfo.fight_force; 
                            retServerData.score = gBattleWorld.serverTotalScores[server] || serverInfo.score; 
                        }
                        
                    }
                } 
            }
            
            var userData = gBattleWorld.getUser(uid);

            resp.data.user_progress = (userData ? userData.progress : 0);
            resp.data.battle_fields = battleFields;
            
            // 检查支持奖励
            var reqCount = req.args.count;
            if( gBattleWorld.isUnderSupportReward() && reqCount 
                && (reqCount == gBattleWorld.count) 
                && (curProgress in gConfBattleWorldSupport) ) {
                var supports = req.args.support;  
                var supportUpdates = {};
                for( var progress in supports ) {
                    var support = supports[progress]; 
                    if( support.got || support.succ ) {
                        continue; 
                    }
                    
                    var supportServer = support.server;
                    var battleFieldId = gBattleWorld.getBattleFieldOfServerInProgress(serverFieldId, supportServer, progress);
                    var serverRanks = gBattleWorld.getBattleFieldHistoryServerRank(serverFieldId, battleFieldId);
                    if( serverRanks.length == 0 ) {
                        continue;
                    }

                    var succ = (+serverRanks[0].server == supportServer) ? 1 : 0;
                    if( !succ ) {
                        continue; 
                    }
                    
                    if( +progress == +curProgress ) {
                        // 晋级赛中每个进度比赛完成之后且只有处于当前进度的支持才能获取奖励
                        supportUpdates[progress] = 1;
                    }else {
                        // 获取胜利但错失领奖
                        supportUpdates[progress] = 0;
                    }
                }

                if( Object.keys(supportUpdates).length > 0 ) {
                    resp.data.support_updates = supportUpdates;
                } 
            }
        }
        
        resp.data.progress_end = gBattleWorld.getEndProgress(); 
        resp.data.server_id = serverId;
        resp.data.register = register;
        resp.data.qualification = qualification;
        resp.data.count = gBattleWorld.count;
    }while(false);

    onReqHandled(res, resp);
}

exports.get_battle_field = function(req, res, resp) {
    var uid = req.uid;
    var serverId = req.args.server;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }
         
        if( !gBattleWorld.haveQualification(serverId, uid) ) {
            resp.code = 1; resp.desc = 'no qualification'; break;
        }

        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }
        
        if( !req.args.user && !gBattleWorld.getPlayer(uid) ) {
            resp.code = 3; resp.desc = 'no player'; break;
        }
        
        var fightForce = 0;
        if( req.args.user ) {
            var user = req.args.user;
            fightForce = user.status.fight_force;
            gBattleWorld.saveTeam(user);
        }

        var serverData = gBattleWorld.getServer(serverId);
        var serverFieldId = serverData.server_field;
        var battleFieldId = serverData.battle_field;
        var mainCity = serverData.main_city;

        var userData = gBattleWorld.getUser(uid);
        var enter = 1;
        if( !userData ) {
            userData = gBattleWorld.addUser(uid, serverFieldId, battleFieldId, mainCity, serverId, fightForce);
        }else if( userData && userData.progress != gBattleWorld.progress ) {
            userData = gBattleWorld.updateUser(uid, serverFieldId, battleFieldId, mainCity, serverId);
        }else {
            enter = 0; 
        }

        var cities = gBattleWorld.getBattleFieldCities(serverFieldId, battleFieldId);

        // 可能更新该战场服务器积分
        gBattleWorld.updateServerScore(serverFieldId, battleFieldId);
        
        var servers = gBattleWorld.genBattleFieldServerRank(serverFieldId, battleFieldId);
        
        resp.data.enter = enter;
        resp.data.message = gBattleWorld.getMessage(serverFieldId, battleFieldId); 
        resp.data.server_score = serverData.score;
        resp.data.servers = servers; 
        resp.data.user = {city:userData.city, score:userData.score, energy:userData.energy, kill:userData.kill};
        resp.data.cities = cities;
    }while(false);

    delete req.args.user;
    onReqHandled(res, resp);
}

exports.get_battle_field_city = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }

        if( !gBattleWorld.getPlayer(uid) ) {
            resp.code = 3; resp.desc = 'no player'; break;
        }

        var city = parseInt(req.args.id);
        if( !(city in cityMove) ) {
            resp.code = 1; resp.desc = 'invalid city'; break;
        }

        var userData = gBattleWorld.getUser(uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'not in war'; break;
        }

        var serverId = gBattleWorld.getUserServerId(uid);
        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }
        
        var serverData = gBattleWorld.getServer(serverId);
        var serverFieldId = serverData.server_field;
        var battleFieldId = serverData.battle_field;
        var mainCity = serverData.main_city;

        var curProgress = gBattleWorld.progress;
        var cityMembers = gBattleWorld.getBattleFieldCityMembers(serverFieldId, battleFieldId, city);
        var members = {};
        for( var id in cityMembers ) {
             var memberData = gBattleWorld.getUser(id);  
             if( !memberData || memberData.progress != curProgress ) {
                continue; 
             }

             members[id] = {
                kill : memberData.kill,
                energy : memberData.energy,
                name : (gBattleWorld.getPlayer(id) ? gBattleWorld.getPlayer(id).user.info.un : ''),
             };
        }

        resp.data.members = members;
    }while(false);

    onReqHandled(res, resp);
}

exports.support = function(req, res, resp) {
    var uid = req.uid;
    do {
        var supports = req.args.support;
        var supportServer = parseInt(req.args.id);
        var supportProgress = parseInt(req.args.progress);
        var serverId = req.args.server;

        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'under war'; break;
        }

        var progress = gBattleWorld.getProgress().progress;
        if( progress == 'register' ) {
            resp.code = 1; resp.desc = 'under register'; break;
        }
        
        var curSupportProgress = gBattleWorld.getCurSupportProgress();
        if( !curSupportProgress || (supportProgress != curSupportProgress) ) {
            resp.code = 1; resp.desc = 'support progress error'; break;
        }

        var serverData = gBattleWorld.getServer(serverId);
        if( !serverData ) {
            resp.code = 1; resp.desc = 'user server not in war'; break;
        }

        var supportServerData = gBattleWorld.getServer(supportServer);
        if( !supportServerData || (serverData.server_field != supportServerData.server_field) ) {
            resp.code = 1; resp.desc = 'invalid support server'; break;
        }
        
        var supportServerFieldId = supportServerData.server_field;
        var supportBattleFieldId = supportServerData.battle_field; 
        if( (supportProgress != 9) ) {
            var servers = gBattleWorld.getBattleFieldHistoryServerRank(supportServerFieldId, supportBattleFieldId);
            if( !servers[0] || (+servers[0].server != supportServer) ) {
                resp.code = 1; resp.desc = 'support server no promotion'; break;
            }
        }

        supportServerData.worth += gConfLevel[req.args.level].BattleWorldSupport 
            * gConfBattleWorldSupport[supportProgress].Gold;
        
        gBattleWorld.addUpdate(util.format('servers.%d', supportServer), 
            supportServerData);
        
        resp.data.count = gBattleWorld.count;
    }while(false);

    gBattleWorld.save();
    onReqHandled(res, resp);
}

exports.get_person_rank = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }

        if( !gBattleWorld.getPlayer(uid) ) {
            resp.code = 3; resp.desc = 'no player'; break;
        }

        var userData = gBattleWorld.getUser(uid); 
        if( !userData || userData.progress != gBattleWorld.progress ) {
            resp.code = 1; resp.desc = 'invalid uid'; break;
        }
        
        var serverId = gBattleWorld.getUserServerId(uid); 
        var serverData = gBattleWorld.getServer(serverId);
        if( !serverData ) {
            resp.code = 1; resp.desc = 'invalid server'; break;
        }

        var rank = gBattleWorld.getCurrentPersonRank(serverData.server_field, serverData.battle_field);
        resp.data.rank = rank;
    }while(false);

    onReqHandled(res, resp);
}

exports.fight = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }

        var enemy = parseInt(req.args.id);
        if( isNaN(enemy) ) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

        if( !gBattleWorld.getPlayer(uid) ) {
            resp.code = 3; resp.desc = 'no user player'; break;
        }

        if( !gBattleWorld.getPlayer(enemy) ) {
            resp.code = 3; resp.desc = 'no enemy player'; break;
        }

        var userData = gBattleWorld.getUser(uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'user not in war'; break;
        }

        var enemyData = gBattleWorld.getUser(enemy);
        if( !enemyData ) {
            resp.code = 1; resp.desc = 'enemy not in war'; break;
        }

        var userServerId = gBattleWorld.getUserServerId(uid);
        var enemyServerId = gBattleWorld.getUserServerId(enemy);
        if( !gBattleWorld.isServerOnCurProgress(userServerId) ) {
            resp.code = 1; resp.desc = 'user server not in current progress'; break;
        }

        if( !gBattleWorld.isServerOnCurProgress(enemyServerId) ) {
            resp.code = 1; resp.desc = 'enemy server not in current progress'; break;
        }

        if( userData.energy <= 0 || enemyData.energy <= 0 ) {
            resp.code = 3; resp.desc = 'not enough energy'; break;
        }
        
        if( userServerId == enemyServerId ) {
            resp.code = 3; resp.desc = 'not enemy'; break;
        }

        var userServerData = gBattleWorld.getServer(userServerId);
        var enemyServerData = gBattleWorld.getServer(enemyServerId);

        var userServerFieldId = userServerData.server_field;
        var userBattleFieldId = userServerData.battle_field;

        var enemyServerFieldId = enemyServerData.server_field;
        var enemyBattleFieldId = enemyServerData.battle_field;

        // 不是同伙
        if( userServerFieldId != enemyServerFieldId || userBattleFieldId != enemyBattleFieldId ) {
            resp.code = 1; resp.desc = 'not in same battle field'; break;
        }

        var serverFieldId = userServerFieldId;
        var battleFieldId = userBattleFieldId;
        
        var enemyCity = +enemyData.city;
        // 进攻路径
        if( cityMove[userData.city].indexOf(enemyCity) < 0 ) {
            resp.code = 3; resp.desc = 'invalid path'; break;
        }

        var isAddAttack = 0;
        var addToWhich = '';
        if( mainCities.indexOf(userData.city) >= 0 ) {
            isAddAttack = 1;
            addToWhich = 'attack';
        }else if( mainCities.indexOf(enemyCity) >= 0 ) {
            isAddAttack = 1;
            addToWhich = 'defence';
        }  
        
        gBattleWorld.fight(uid, enemy, isAddAttack, addToWhich, function(battleReport) {
            if( !battleReport ) {
                resp.code = 1; resp.desc = 'pvp error';
                onReqHandled(res, resp);
                return;
            }
            
            var userCostEnergy = 0;
            var enemyCostEnergy = 0;

            var userName = gBattleWorld.getPlayer(uid).user.info.un;
            var enemyName = gBattleWorld.getPlayer(enemy).user.info.un;
            var succ = battleReport.success;
            if( succ ) {
                enemyCostEnergy = gConfGlobal.BattleWorldFailEnergy;
                var healthPercent = battleReport.atk_remain_health/battleReport.atk_team_health;
                userCostEnergy = Math.min(Math.floor(Math.max(10, 50*(1 - healthPercent))), 40); 

                var oldEnemyKill = enemyData.kill;
                userData.kill += 1;
                enemyData.kill = 0;
                userData.score += gConfGlobal.BattleWorldWinScore;
                enemyData.score += gConfGlobal.BattleWorldFailScore;

                if( userData.kill >= 10 ) {
                    gBattleWorld.addMessage(serverFieldId,battleFieldId,[userName, userData.kill]);
                }
                
                if( oldEnemyKill >= 10 ) {
                    gBattleWorld.addMessage(serverFieldId,battleFieldId,[userName, enemyName, oldEnemyKill]);
                }
                
            }else{
                userCostEnergy = gConfGlobal.BattleWorldFailEnergy;
                var healthPercent = battleReport.def_remain_health/battleReport.def_team_health;
                enemyCostEnergy = Math.min(Math.floor(Math.max(10, 50*(1 - healthPercent))), 40); 

                userData.kill = 0;
                userData.score += gConfGlobal.BattleWorldFailScore;
                enemyData.score += gConfGlobal.BattleWorldWinScore;
            }
            

            if( enemyCostEnergy > enemyData.energy ) {
                enemyCostEnergy = enemyData.energy;
            }

            if( userCostEnergy > userData.energy ) {
                userCostEnergy = userData.energy;
            }

            // 给对手的消息
            var report = {
                'name' : userName, 
                'time' : common.getTime(), 
                'succ' : succ, 
                'energy': enemyCostEnergy,
                'score': succ ? gConfGlobal.BattleWorldFailScore : gConfGlobal.BattleWorldWinScore,
                'replay': gReplay.addReplay(battleReport),
            };
            
            gBattleWorld.addReport(enemy, report);
            enemyData.energy -= enemyCostEnergy;
            userData.energy -= userCostEnergy;
            
            var  canOccupy = true; 
            // 没体力需要回城
            if( userData.energy <= 0 ) {
                gBattleWorld.backHome(serverFieldId, battleFieldId, uid); 
                canOccupy = false; 
            }
            
            if( enemyData.energy <= 0 ) {
                gBattleWorld.backHome(serverFieldId, battleFieldId, enemy);
            }else {
                canOccupy = false;
            }
            
            if( canOccupy && mainCities.indexOf(enemyCity) < 0 ) {
                var cityOccupiedServer = gBattleWorld.cityOccupiedServer(serverFieldId, battleFieldId, enemyCity);
                if( !cityOccupiedServer ) {
                    // 占领
                    gBattleWorld.move(serverFieldId, battleFieldId, uid, enemyCity);
                }
            }
            
            gBattleWorld.addUpdate(util.format('users.%d', uid), userData);
            gBattleWorld.addUpdate(util.format('users.%d', enemy), enemyData);

            resp.data.battle = battleReport;
            resp.data.energy = -userCostEnergy;

            gBattleWorld.save();
            onReqHandled(res, resp);
        });
        return;
    }while(false);

    onReqHandled(res, resp);
}

exports.move = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }

        if( !gBattleWorld.getPlayer(uid) ) {
            resp.code = 3; resp.desc = 'no player'; break;
        }

        if( isNaN(req.args.city) || !(req.args.city in cityMove) ) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

        var city = parseInt(req.args.city);
        var userData = gBattleWorld.getUser(uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'not in war'; break;
        }
        
        if( userData.energy <= 0 ) {
            resp.code = 3; resp.desc = 'no energy'; break;
        }

        if( +userData.city == city ) {
            resp.code = 1; resp.desc = 'move self'; break;
        }

        var serverId = gBattleWorld.getUserServerId(uid);
        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }

        var serverData = gBattleWorld.getServer(serverId);
        var serverFieldId = serverData.server_field;
        var battleFieldId = serverData.battle_field;
        var mainCity = serverData.main_city;

        if( mainCities.indexOf(city) >= 0 && mainCity != city ) {
            resp.code = 1; resp.desc = 'other team main city'; break;
        }
        
        var cityOccupiedServer = gBattleWorld.cityOccupiedServer(serverFieldId, battleFieldId, city);
        // 不是自己服务器占领的城
        if( cityOccupiedServer && (cityOccupiedServer != serverId) ) {
            resp.code = 3; resp.desc = 'occupying by other'; break;
        }

        if( cityMove[userData.city].indexOf(city) < 0 ) {
            resp.code = 1; resp.desc = 'invalid city move'; break;
        }

        gBattleWorld.move(serverFieldId, battleFieldId, uid, +city);
        gBattleWorld.save();
    }while(false);

    onReqHandled(res, resp);
}

exports.get_energy = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }

        if( !gBattleWorld.getPlayer(uid) ) {
            resp.code = 3; resp.desc = 'no player'; break;
        }

        var city = parseInt(req.args.city);
        var userData = gBattleWorld.getUser(uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'not in war'; break;
        }
        
        var serverId = gBattleWorld.getUserServerId(uid);
        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }

        var serverData = gBattleWorld.getServer(serverId);
        var serverFieldId = serverData.server_field;
        var battleFieldId = serverData.battle_field;
        var mainCity = serverData.main_city;
        var userData = gBattleWorld.getUser(req.uid);

        if( mainCities.indexOf(userData.city) < 0 ) {
            resp.code = 1; resp.desc = 'not in main city'; break;
        }
        
        var maxEnergy = gConfGlobal.BattleWorldPersonEnernyMax;
        if( userData.energy >= maxEnergy ) {
            resp.code = 1; resp.desc = 'full'; break;
        }

        var energyGot = maxEnergy - userData.energy;
        if( energyGot > req.args.energy ) {
            energyGot = req.args.energy;
        }

        userData.energy += energyGot;
        gBattleWorld.addUpdate(util.format('users.%d', uid), userData);

        resp.data.energy_got = energyGot;

        gBattleWorld.save();
    }while(false);

    onReqHandled(res, resp);
}

exports.end_war = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'under war'; break;
        }

        var userData = gBattleWorld.getUser(req.uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'not in war'; break;
        }
        
        if( (gBattleWorld.progress == 'register') || 
            userData.progress != gBattleWorld.progress ) {
            resp.code = 1; resp.desc = 'not in progress'; break;
        }

        var serverId = gBattleWorld.getUserServerId(uid);
        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }
        
        var serverData = gBattleWorld.getServer(serverId);
        var serverFieldId = serverData.server_field;
        var battleFieldId = serverData.battle_field;
        var mainCity = serverData.main_city;

         
        var user = {
            name : gBattleWorld.getPlayer(uid).user.info.un,
            score : userData.score + serverData.score, 
        }     

        var servers = gBattleWorld.genBattleFieldServerRank(serverFieldId, battleFieldId);

        var topUsers = [];
        var battleFieldIndex = util.format('%d_%d', serverFieldId, battleFieldId);

        var top = gBattleWorld.topOnes[battleFieldIndex];
        if( top ) {
            for( var i = 0, len = top.length; i < len; i++ ) {
                var topId = top[i];
                topUsers.push({
                    'uid': topId, 
                    'name': (gBattleWorld.players[topId] ? gBattleWorld.players[topId].user.info.un : '')
                }); 
            }
        }

        var userScore = user.score;
        resp.data.soul = Math.floor(90000*userScore/(userScore + 30000)) + 10000;
        resp.data.user = user;
        resp.data.top = topUsers;

        gBattleWorld.save();
    }while(false);

    onReqHandled(res, resp);
}

exports.get_reward = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'under war'; break;
        }

        var userData = gBattleWorld.getUser(req.uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'not in war'; break;
        }

        if( (gBattleWorld.progress == 'register') || 
            userData.progress != gBattleWorld.progress ) {
            resp.code = 1; resp.desc = 'not in progress'; break;
        }

        var serverId = gBattleWorld.getUserServerId(uid);
        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }
        
        var haveGotRewardProgress = req.args.reward;
        if( haveGotRewardProgress && (haveGotRewardProgress == gBattleWorld.progress ) ) {
            resp.code = 1; resp.desc = 'have got'; break;
        }
        
        var serverData = gBattleWorld.getServer(serverId);
        var serverFieldId = serverData.server_field;
        var battleFieldId = serverData.battle_field;
        var mainCity = serverData.main_city;

 
        var top = [];
        var battleFieldIndex = util.format('%d_%d', serverFieldId, battleFieldId);
        if( battleFieldIndex in gBattleWorld.topOnes ) {
            top = gBattleWorld.topOnes[battleFieldIndex];
        }

        var userScore = userData.score + serverData.score; 
        resp.data.soul = Math.floor(90000*userScore/(userScore + 30000)) + 10000;
        resp.data.topone = top.indexOf(uid) >= 0 ? 1: 0 ;   // 是否神将 
        resp.data.progress = gBattleWorld.progress;

        gBattleWorld.save(); 

    }while(false);

    onReqHandled(res, resp);
}

exports.get_final_reward = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'under war'; break;
        }
        
        if( (gBattleWorld.progress == 'register') || 
            gBattleWorld.progress != 1 || !gBattleWorld.end ) {
            resp.code = 1; resp.desc = 'final progress not end'; break;
        }

        var serverId = req.args.server;
        if( !gBattleWorld.haveQualification(serverId, uid) ) {
            resp.code = 1; resp.desc = 'no qualification'; break;
        }
        
        var serverData = gBattleWorld.getServer(serverId);
        if( !serverData ) {
            resp.code = 1; resp.desc = 'server not in war'; break;
        }
        
        var serverFieldId = serverData.server_field;
        var battleFieldId = serverData.battle_field;
        
        var rank = 27;
        if( 1 == battleFieldId ) {
            // 冠军判断
            var servers = gBattleWorld.getBattleFieldHistoryServerRank(serverFieldId, battleFieldId);
            if( +servers[0].server == serverId ) {
                rank = 1; 
            }else {
                rank = 3; 
            }
        }else {
            var progresses = [3, 9];
            for( var i = 0, len = progresses.length; i < len; i++ ) {
                var progress = progresses[i];
                var battleFields = fightProgressMap[progress];
                if( battleFields.indexOf(+battleFieldId) < 0 ) {
                    continue;
                }

                rank = progress*3;
                break;
            }
        }

        var rewardConf = gConfBattleWorldReward[rank];
        if( !rewardConf ) {
            resp.code = 1; resp.desc = 'rank error '; break;
        }

        resp.data.awards = [rewardConf.Award1];  

    }while(false);

    onReqHandled(res, resp);
}

exports.get_report = function(req, res, resp) {
    var uid = req.uid;
    do {
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }

        var userData = gBattleWorld.getUser(uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'not in war'; break;
        }
        
        var serverId = gBattleWorld.getUserServerId(uid);
        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }

        resp.data.report = gBattleWorld.getReport(uid);

    }while(false);

    onReqHandled(res, resp);
}

exports.get_replay = function(req, res, resp) {
    var uid = req.uid;
    do{
        if( gBattleWorld.calculating ) {
            resp.data.calculating = 1; break;
        }

        if( !gBattleWorld.isUnderWar() ) {
            resp.code = 1; resp.desc = 'not under war'; break;
        }

        var userData = gBattleWorld.getUser(uid);
        if( !userData ) {
            resp.code = 1; resp.desc = 'not in war'; break;
        }
        
        var serverId = gBattleWorld.getUserServerId(uid);
        if( !gBattleWorld.isServerOnCurProgress(serverId) ) {
            resp.code = 1; resp.desc = 'server not in current progress'; break;
        }

        gReplay.getReplay(req.args.id, function(battle){
            if( battle ) {
                resp.data.battle = battle;
            }

            onReqHandled(res, resp);
        });
        
        return;
    }while(false);

    onReqHandled(res, resp);
}

exports.BattleWorld = BattleWorld;
